package nio.demo;


import nio.bytebuffer.ByteBufferUtil;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author ZH
 */
public class Server {
    public static void main(String[] args) throws IOException {
        Logger logger = LoggerFactory.getLogger(Server.class);
        // 1 创建selector 管理多个channel
        Selector selector = Selector.open();
        //创建客户端服务器
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        serverSocketChannel.configureBlocking(false); //切换到非阻塞模式
        // 2 把channel 注册 到selector中
        // selectionKey 就是事件发生后,通过它可以得到是 哪个channel 发生 的什么事件
        SelectionKey sscKey = serverSocketChannel.register(selector, 0, null);
        //key 只关注accept事件
        sscKey.interestOps(SelectionKey.OP_ACCEPT);
        logger.debug("register key : {}",sscKey);
        //绑定端口
        serverSocketChannel.bind(new InetSocketAddress(8080));
        //建立链接集合
        while (true){
            // 3. select 方法 没有事件发生就阻塞,有事件发生就会继续执行
            // select  在事件未处理时,不会阻塞  事件发生后 要么处理,要么取消,不能不理
            selector.select();
            // 4. 处理事件
            Set<SelectionKey> selectionKeys = selector.selectedKeys(); // 所有发生的事件
            Iterator<SelectionKey> iterator = selectionKeys.iterator();
            while (iterator.hasNext()){
                SelectionKey key = iterator.next();
                //处理key的时候 一定要从selectionKeys中删除
                iterator.remove();
                logger.debug("key : {}",key);
                //5 区分事件类型
                if (key.isAcceptable()) {
                    ServerSocketChannel channel = (ServerSocketChannel)key.channel();
                    SocketChannel sc = channel.accept();
                    logger.debug("{}",sc);
                    sc.configureBlocking(false); // 非阻塞模式
                    ByteBuffer buffer = ByteBuffer.allocate(16); //attachment 附件
                    //把buffer附件到selectionKey上   这样就能一个channel对应一个buffer
                    SelectionKey scKey = sc.register(selector, 0, buffer);// 注册
                    scKey.interestOps(SelectionKey.OP_READ);
                }else if(key.isReadable()){
                    try {
                        SocketChannel channel = (SocketChannel)key.channel(); // 拿到触发事件的channel
                        //获取selectionKey的附件
                        ByteBuffer buffer = (ByteBuffer)key.attachment();
                        int read = channel.read(buffer); // 如果是正常断开,read为-1
                        if (read == -1){
                            key.cancel();
                        }else{
                            System.out.println("当前buffer长度为"+buffer.position());
                            split(buffer);
                            if (buffer.position() == buffer.limit()){
                                ByteBuffer newBuffer = ByteBuffer.allocate(buffer.capacity()*2); //容量翻倍
                                buffer.flip();
                                newBuffer.put(buffer);
                                key.attach(newBuffer);
                            }
                        }
                    }catch (IOException e){
                        e.printStackTrace();
                        key.cancel();
                    }
                }
            }
        }
    }
    public static void split(ByteBuffer source){
        source.flip(); //切换成读

        for (int i = 0; i < source.limit(); i++) {
            if (source.get(i) =='\n'){
                int length = i - source.position() + 1;
                ByteBuffer target = ByteBuffer.allocate(length);
                for (int j = 0; j < length; j++) {
                    target.put(source.get());
                }
                ByteBufferUtil.debugAll(target);
            }
        }
        source.compact(); //切换成写
    }
}
